From fcf4e106d0be62c04c62393632bb8b5a52c2dc8a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 25 Oct 2006 11:50:54 +0100 Subject: [PATCH] [HVM] Move ACPI timer to HV, which is the last platform timer in Qemu. We found Vista polls ACPI timer very frequently (about 15 times averagely) when handling timer (RTC @ 64HZ) interrupt routine. Though the exact reason is known, it should be related to system time adjustment. When it's in Qemu, the overhead is big. After moving, Vista's idle overhead decreases dramatically from ~10% to 0.9%.=20 Another benefit is that Vista can only pass Performance rating with this patch. The root cause is that ACPI timer in Qemu isn't synchronous with other platform timer in HV, which results in Vista complains "can't measure TSC frequency". This patch changes vpit.h to vpt.h, for it not only has pit structure in it, but other platform timer's structure. Another change is moving ACPI timer and related address from acpi.h to ioreq.h, which can be shared by HV and ACPI firmware. Signed-off-by: Xiaowei Yang --- tools/firmware/acpi/acpi_fadt.h | 9 ++-- xen/arch/x86/hvm/Makefile | 1 + xen/arch/x86/hvm/hvm.c | 3 +- xen/arch/x86/hvm/i8254.c | 2 +- xen/arch/x86/hvm/io.c | 2 +- xen/arch/x86/hvm/pmtimer.c | 63 +++++++++++++++++++++++ xen/arch/x86/hvm/rtc.c | 2 +- xen/arch/x86/hvm/svm/svm.c | 3 ++ xen/arch/x86/hvm/vmx/vmx.c | 3 ++ xen/include/asm-x86/hvm/domain.h | 2 +- xen/include/asm-x86/hvm/{vpit.h => vpt.h} | 24 ++++++--- xen/include/public/hvm/ioreq.h | 4 ++ 12 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 xen/arch/x86/hvm/pmtimer.c rename xen/include/asm-x86/hvm/{vpit.h => vpt.h} (89%) diff --git a/tools/firmware/acpi/acpi_fadt.h b/tools/firmware/acpi/acpi_fadt.h index d1ecea5588..f30a1dac98 100644 --- a/tools/firmware/acpi/acpi_fadt.h +++ b/tools/firmware/acpi/acpi_fadt.h @@ -18,6 +18,8 @@ #ifndef _FADT_H_ #define _FADT_H_ +#include + // // FADT Definitions, see ACPI 2.0 specification for details. // @@ -51,7 +53,9 @@ // // Fixed Feature Flags // -#define ACPI_FIXED_FEATURE_FLAGS (ACPI_PROC_C1|ACPI_SLP_BUTTON|ACPI_WBINVD|ACPI_PWR_BUTTON|ACPI_FIX_RTC) +#define ACPI_FIXED_FEATURE_FLAGS (ACPI_PROC_C1 | ACPI_SLP_BUTTON | \ + ACPI_WBINVD | ACPI_PWR_BUTTON | \ + ACPI_FIX_RTC | ACPI_TMR_VAL_EXT) // // PM1A Event Register Block Generic Address Information @@ -59,7 +63,6 @@ #define ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO #define ACPI_PM1A_EVT_BLK_BIT_WIDTH 0x20 #define ACPI_PM1A_EVT_BLK_BIT_OFFSET 0x00 -#define ACPI_PM1A_EVT_BLK_ADDRESS 0x000000000000c010 // // PM1B Event Register Block Generic Address Information @@ -75,7 +78,6 @@ #define ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO #define ACPI_PM1A_CNT_BLK_BIT_WIDTH 0x10 #define ACPI_PM1A_CNT_BLK_BIT_OFFSET 0x00 -#define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04) // // PM1B Control Register Block Generic Address Information @@ -100,7 +102,6 @@ #define ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO #define ACPI_PM_TMR_BLK_BIT_WIDTH 0x20 #define ACPI_PM_TMR_BLK_BIT_OFFSET 0x00 -#define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08) // // General Purpose Event 0 Register Block Generic Address diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index 37623ff5eb..843a9232bf 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -5,6 +5,7 @@ obj-y += hvm.o obj-y += i8254.o obj-y += i8259.o obj-y += rtc.o +obj-y += pmtimer.o obj-y += instrlen.o obj-y += intercept.o obj-y += io.o diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 47d7ca46c4..f950d05295 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -285,6 +285,7 @@ void hvm_setup_platform(struct domain* d) pt_timer_fn, v, v->processor); pit_init(v, cpu_khz); rtc_init(v, RTC_PORT(0), RTC_IRQ); + pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS); } void pic_irq_request(void *data, int level) diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c index 5f27ee25b2..464ddee8f9 100644 --- a/xen/arch/x86/hvm/i8254.c +++ b/xen/arch/x86/hvm/i8254.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include /* Enable DEBUG_PIT may cause guest calibration inaccuracy */ diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 8993572e10..a1ce8ddf33 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/xen/arch/x86/hvm/pmtimer.c b/xen/arch/x86/hvm/pmtimer.c new file mode 100644 index 0000000000..e0c93536ea --- /dev/null +++ b/xen/arch/x86/hvm/pmtimer.c @@ -0,0 +1,63 @@ +#include +#include +#include + +#define TMR_STS (1 << 0) +static void pmt_update_status(void *opaque) +{ + PMTState *s = opaque; + s->pm1_status |= TMR_STS; + + /* TODO: When TMR_EN == 1, generate a SCI event */ + + set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER); +} + +static int handle_pmt_io(ioreq_t *p) +{ + struct vcpu *v = current; + PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; + uint64_t curr_gtime; + + if (p->size != 4 || + p->pdata_valid || + p->type != IOREQ_TYPE_PIO){ + printk("HVM_PMT: wrong PM timer IO\n"); + return 1; + } + + if (p->dir == 0) { /* write */ + /* PM_TMR_BLK is read-only */ + return 1; + } else if (p->dir == 1) { /* read */ + curr_gtime = hvm_get_guest_time(s->vcpu); + s->pm1_timer += ((curr_gtime - s->last_gtime) * s->scale) >> 32; + p->u.data = s->pm1_timer; + s->last_gtime = curr_gtime; + return 1; + } + return 0; +} + +void pmtimer_init(struct vcpu *v, int base) +{ + PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; + + s->pm1_timer = 0; + s->pm1_status = 0; + s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v); + s->vcpu = v; + + init_timer(&s->timer, pmt_update_status, s, v->processor); + /* ACPI supports a 32-bit power management timer */ + set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER); + + register_portio_handler(base, 4, handle_pmt_io); +} + +void pmtimer_deinit(struct domain *d) +{ + PMTState *s = &d->arch.hvm_domain.pl_time.vpmt; + + kill_timer(&s->timer); +} diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 210168c26b..0f5e11986e 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -23,7 +23,7 @@ */ #include -#include +#include #include #include #include diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 92167d74fb..88c0802425 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -922,6 +922,7 @@ static void svm_relinquish_guest_resources(struct domain *d) kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer); rtc_deinit(d); + pmtimer_deinit(d); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -937,6 +938,7 @@ static void svm_migrate_timers(struct vcpu *v) struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc; + struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt; if ( pt->enabled ) { @@ -947,6 +949,7 @@ static void svm_migrate_timers(struct vcpu *v) migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor); migrate_timer(&vrtc->second_timer, v->processor); migrate_timer(&vrtc->second_timer2, v->processor); + migrate_timer(&vpmt->timer, v->processor); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 476f8beae9..ac1be73556 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -147,6 +147,7 @@ static void vmx_relinquish_guest_resources(struct domain *d) kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer); rtc_deinit(d); + pmtimer_deinit(d); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -489,6 +490,7 @@ void vmx_migrate_timers(struct vcpu *v) { struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc; + struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt; if ( pt->enabled ) { @@ -499,6 +501,7 @@ void vmx_migrate_timers(struct vcpu *v) migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor); migrate_timer(&vrtc->second_timer, v->processor); migrate_timer(&vrtc->second_timer2, v->processor); + migrate_timer(&vpmt->timer, v->processor); } static void vmx_store_cpu_guest_regs( diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 6561519cb1..0ebec779c1 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -23,7 +23,7 @@ #define __ASM_X86_HVM_DOMAIN_H__ #include -#include +#include #include #include #include diff --git a/xen/include/asm-x86/hvm/vpit.h b/xen/include/asm-x86/hvm/vpt.h similarity index 89% rename from xen/include/asm-x86/hvm/vpit.h rename to xen/include/asm-x86/hvm/vpt.h index 83b1af2622..ada8936af7 100644 --- a/xen/include/asm-x86/hvm/vpit.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -1,5 +1,5 @@ /* - * vpit.h: Virtual PIT definitions + * vpt.h: Virtual Platform Timer definitions * * Copyright (c) 2004, Intel Corporation. * @@ -17,8 +17,8 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __ASM_X86_HVM_VPIT_H__ -#define __ASM_X86_HVM_VPIT_H__ +#ifndef __ASM_X86_HVM_VPT_H__ +#define __ASM_X86_HVM_VPT_H__ #include #include @@ -70,7 +70,17 @@ typedef struct RTCState { struct vcpu *vcpu; struct periodic_time *pt; } RTCState; - + +#define FREQUENCE_PMTIMER 3579545 +typedef struct PMTState { + uint32_t pm1_timer; + uint32_t pm1_status; + uint64_t last_gtime; + struct timer timer; + uint64_t scale; + struct vcpu *vcpu; +} PMTState; + /* * Abstract layer of periodic time, one short time. */ @@ -95,7 +105,7 @@ struct pl_time { /* platform time */ struct periodic_time periodic_tm; struct PITState vpit; struct RTCState vrtc; - /* TODO: ACPI time */ + struct PMTState vpmt; }; static __inline__ s_time_t get_scheduled( @@ -132,8 +142,10 @@ extern void destroy_periodic_time(struct periodic_time *pt); void pit_init(struct vcpu *v, unsigned long cpu_khz); void rtc_init(struct vcpu *v, int base, int irq); void rtc_deinit(struct domain *d); +void pmtimer_init(struct vcpu *v, int base); +void pmtimer_deinit(struct domain *d); int is_rtc_periodic_irq(void *opaque); void pt_timer_fn(void *data); void pit_time_fired(struct vcpu *v, void *priv); -#endif /* __ASM_X86_HVM_VPIT_H__ */ +#endif /* __ASM_X86_HVM_VPT_H__ */ diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h index 8e92b004b1..992505e1c5 100644 --- a/xen/include/public/hvm/ioreq.h +++ b/xen/include/public/hvm/ioreq.h @@ -86,6 +86,10 @@ struct buffered_iopage { }; /* sizeof this structure must be in one page */ typedef struct buffered_iopage buffered_iopage_t; +#define ACPI_PM1A_EVT_BLK_ADDRESS 0x000000000000c010 +#define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04) +#define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08) + #endif /* _IOREQ_H_ */ /* -- 2.30.2